// ========================================================================
// Copyright (c) 2009 Mort Bay Consulting Pty. Ltd.
// ------------------------------------------------------------------------
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
// The Eclipse Public License is available at
// http://www.eclipse.org/legal/epl-v10.html
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
// You may elect to redistribute this code under either of these licenses.
// ========================================================================

package com.globallogic.socialnetwork.util;

import java.io.File;
import java.net.URI;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.List;
import java.util.jar.Attributes.Name;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.jar.Manifest;

import org.apache.commons.collections.CollectionUtils;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
import org.eclipse.jetty.util.resource.Resource;
import org.eclipse.jetty.webapp.AbstractConfiguration;
import org.eclipse.jetty.webapp.FragmentConfiguration;
import org.eclipse.jetty.webapp.JarScanner;
import org.eclipse.jetty.webapp.TagLibConfiguration;
import org.eclipse.jetty.webapp.WebAppContext;
import org.eclipse.jetty.webapp.WebInfConfiguration;

/**
 * This class is copy of {@link org.eclipse.jetty.webapp.MetaInfConfiguration}
 * with improvements for loading tld libraries from surefire booter jar metainf.
 * {@link TagLibConfiguration} configures all the ContextListeners form the tld
 * files. Happens so that it used only in jsf, but jetty doen't handles
 * manifests. Maven runs tests with his onw classloader, and creates
 * surefirebooter.jar with manifest having all the classpath. See
 * UrlClassLoader.getUrls().
 * 
 * @author ievgen.nekrashevych
 */
public class SurefireConfiguration extends AbstractConfiguration {
	private static final Logger LOG = Log
			.getLogger(SurefireConfiguration.class);

	public static final String METAINF_TLDS = TagLibConfiguration.TLD_RESOURCES;
	public static final String METAINF_FRAGMENTS = FragmentConfiguration.FRAGMENT_RESOURCES;
	public static final String METAINF_RESOURCES = WebInfConfiguration.RESOURCE_URLS;

	@Override
	public void preConfigure(final WebAppContext context) throws Exception {
		ArrayList<Resource> jars = new ArrayList<Resource>();

		// XXX here it goes!!!
		ClassLoader l = ClassLoader.getSystemClassLoader();
		if (l instanceof URLClassLoader) {
			URL[] urls = ((URLClassLoader) l).getURLs();
			for (URL url : urls) {
				if (url.getPath().contains("surefire")
						&& url.getPath().endsWith("jar")) {
					File f = new File(url.getPath().replaceAll("%20", " "));
					JarFile jarFile = new JarFile(f);
					Manifest mf = jarFile.getManifest();
					String[] cp = mf.getMainAttributes()
							.getValue(Name.CLASS_PATH).split(" ");
					for (String c : cp) {
						jars.add(Resource.newResource(c, false));
					}
				}
			}
		}
		if (CollectionUtils.isEmpty(jars)) {
			return;
		}
		JarScanner scanner = new JarScanner() {
			@Override
			public void processEntry(URI jarUri, JarEntry entry) {
				try {
					SurefireConfiguration.this.processEntry(context, jarUri,
							entry);
				} catch (Exception e) {
					LOG.warn("Problem processing jar entry " + entry, e);
				}
			}
		};

		// Scan jars for META-INF information
		if (jars != null) {
			URI[] uris = new URI[jars.size()];
			int i = 0;
			for (Resource r : jars) {
				uris[i++] = r.getURI();
			}
			scanner.scan(null, uris, true);
		}
	}

	@Override
	public void postConfigure(WebAppContext context) throws Exception {
		context.setAttribute(METAINF_FRAGMENTS, null);
		context.setAttribute(METAINF_RESOURCES, null);
		context.setAttribute(METAINF_TLDS, null);
	}

	public void addResource(WebAppContext context, String attribute,
			Resource jar) {
		@SuppressWarnings("unchecked")
		List<Resource> list = (List<Resource>) context.getAttribute(attribute);
		if (list == null) {
			list = new ArrayList<Resource>();
			context.setAttribute(attribute, list);
		}
		if (!list.contains(jar))
			list.add(jar);
	}

	protected void processEntry(WebAppContext context, URI jarUri,
			JarEntry entry) {
		String name = entry.getName();

		if (!name.startsWith("META-INF/"))
			return;

		try {
			if (name.equals("META-INF/web-fragment.xml")
					&& context.isConfigurationDiscovered()) {
				addResource(context, METAINF_FRAGMENTS,
						Resource.newResource(jarUri));
			} else if (name.equals("META-INF/resources/")
					&& context.isConfigurationDiscovered()) {
				addResource(
						context,
						METAINF_RESOURCES,
						Resource.newResource("jar:" + jarUri
								+ "!/META-INF/resources"));
			} else {
				String lcname = name.toLowerCase();
				if (lcname.endsWith(".tld")) {
					addResource(context, METAINF_TLDS,
							Resource.newResource("jar:" + jarUri + "!/" + name));
				}
			}
		} catch (Exception e) {
			context.getServletContext().log(jarUri + "!/" + name, e);
		}
	}
}
